package initialize

import (
	"fmt"
	"sync"

	"github.com/astaxie/beego/logs"
	"github.com/batchcorp/rabbit"
	"github.com/streadway/amqp"
)

type RabbitOption struct {
	queueName    string // fmt.Sprintf(queueName, origin[i], subDepth)
	exchangeName string // binance
}

// Base info
func NewRabbitOption(queueName, exchangeName string) *RabbitOption {
	return &RabbitOption{
		queueName:    queueName,
		exchangeName: exchangeName,
	}
}

type RabbitClientMgr struct {
	option  Option
	Clients map[string]*rabbit.Rabbit
	mu      sync.RWMutex
}

// Open
func (r *RabbitClientMgr) dial(rabbitOption *RabbitOption) {

	url := fmt.Sprintf("amqp://%s:%s@%s:%s",
		r.option.RabbitMQOption.UserName,
		r.option.RabbitMQOption.Password,
		r.option.RabbitMQOption.Host,
		r.option.RabbitMQOption.Port,
	)

	client, err := rabbit.New(&rabbit.Options{
		Mode:         rabbit.Both,
		URLs:         []string{url},
		QueueName:    rabbitOption.queueName,
		AutoAck:      true,
		QueueDurable: true,
		QueueDeclare: true,
		Bindings: []rabbit.Binding{
			rabbit.Binding{
				ExchangeDurable: true,
				ExchangeDeclare: true,
				ExchangeName:    rabbitOption.exchangeName,
				ExchangeType:    amqp.ExchangeDirect,
				BindingKeys:     []string{rabbitOption.queueName},
			},
		},
		QueueArgs: map[string]interface{}{"x-dead-letter-exchange": "dlx"},
	})
	if err != nil {
		logs.Info("unable to instantiate rabbit: err", err)
	}

	r.mu.Lock()
	defer r.mu.Unlock()
	r.Clients[rabbitOption.queueName] = client

}

// rabbit-int
func (r *RabbitClientMgr) Init(option Option) {
	r.option = option
}

// rabbit-set
func (r *RabbitClientMgr) SetClient(rabbitOption *RabbitOption) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.dial(rabbitOption)
}

// rabbit-get
func (r *RabbitClientMgr) GetClient(rabbitOption *RabbitOption) *rabbit.Rabbit {

	r.mu.RLock()
	client, ok := r.Clients[rabbitOption.queueName]
	r.mu.RUnlock()

	if !ok {
		r.dial(rabbitOption)
	} else {
		if client.Conn.IsClosed() {
			fmt.Println("[GetClient-status]", client.Conn.IsClosed())
			r.dial(rabbitOption)
		}
	}
	return r.Clients[rabbitOption.queueName]
}

// remove
func (r *RabbitClientMgr) RemoveClient(rabbitOption *RabbitOption) {

	r.mu.Lock()
	defer r.mu.Unlock()
	_, ok := r.Clients[rabbitOption.queueName]
	if !ok {
		return
	}
	delete(r.Clients, rabbitOption.queueName)
}
